/*
 * File:   file_system.h
 * Author: dolphinigle
 *
 * Created on December 3, 2011, 3:12 PM
 */

#ifndef FILE_SYSTEM_H
#define	FILE_SYSTEM_H

#include <algorithm>
#include <list>
#include <string>
using std::pair;
using std::list;
using std::string;

class FileSystem {
public:
  // Loads a filesystem
  FileSystem(string filename);

  // Creates a new filesystem.
  static string Format(string filename, size_t size);

  string IsExist(string path);
  string Ls(string path);
  string Mkdir(string path);
  string Rm(string path);
  string Cp1(string path, string real_path);
  string Cp2(string realpath, string path);
  string Cat(string path);

  // Closes this filesystem.
  string Close();

  // Describes this filesystem.
  string Status();

private:
  static const int kMetadataSize = 2000;
  static const int kIntegerLength = 10;

  // Filename of this filesystem.
  string filename_;

  // Length
  int data_length_;

  // All directories. name is full: /irvan/. / is considered a directory that
  // cannot be removed.
  list<string> dirs_;

  typedef list<string>::iterator DIt;

  // All files: name, offset, length. name is full: /irvan/irvan.txt
  list<pair<string, pair<int,int> > > files_;

  typedef list<pair<string, pair<int,int> > >::iterator FIt;

  // Offset to the location of bitmaps from beginning.
  int bitmask_offset_;

  // Offset to the location of data from beginning.
  int data_offset_;

  FILE* handle_;

  // Here's the filesystem format:
  // All integers in the filesystem is of kIntegerLength length.
  // Tokens are not separated by |, it's only for clarity in the explanations
  // below.

  // Length of metadata is constant kMetadataSize.

  // The first kIntegerLength bytes are the length of the data.
  // Next, followed by an integer denoting the number of directories.
  // Next are directories in this format:
  // Length_of_total_dir_name|dir_name
  // Example: 00000007|/irvan/

  // Next are files in this format:
  // Length_of_total_file_name|file_name|file_offset|file_size

  // For example, a file with integer length = 2 may look like this:
  // NOte: | for example only, in the real file there are no '|'
  // 12|02|01|/|07|/irvan/|01|11|/irvan/a.in|02|04|....

  // It means that the data length is 12, there are 2 directories:
  // the first one has a name of length 1, its name is /
  // the second one has a name of length 7, its name is /irvan/

  // Then, there are 1 file.
  // Its name is of length 11, its name is /irvan/a.in
  // Its offset is 2
  // Its length is 4

  // After all the metadatas, the data looks like this:
  // 001111000000|00abcd000000
  // The first 12 character are bitmask on whether the corresponding memory
  // has been used. The next 12 characters are the data storage.
  // In this case, /irvan/a.in is located on bytes 2 through 5, which is
  // consistent.

  // Writes in integer to file
  void WriteInt(FILE* handle, int i);

  // Reads an integer from file
  int ReadInt(FILE* handle);

  // Private constructor to use by Format only.
  FileSystem();

  FileSystem(const FileSystem& orig) {
  }

  bool operator=(const FileSystem& orig) {
  }
};

#endif	/* FILE_SYSTEM_H */

